package parser

import (
	"fmt"
	"strconv"

	"gitee.com/yanxingshuyuan/ming/ast"
	"gitee.com/yanxingshuyuan/ming/lexer"
	"gitee.com/yanxingshuyuan/ming/token"
)

type Parser struct {
	lexer *lexer.Lexer

	token token.Token
	peek  token.Token

	errors []string

	prefixParseFns map[token.TokenType]prefixParseFn
	infixParseFns  map[token.TokenType]infixParseFn
}

type (
	prefixParseFn func() ast.Expr
	infixParseFn  func(ast.Expr) ast.Expr
)

func NewParser(l *lexer.Lexer) *Parser {
	p := &Parser{
		lexer:  l,
		errors: []string{},
	}
	// 注册parse函数
	p.prefixParseFns = make(map[token.TokenType]prefixParseFn)
	p.registerPrefix(token.TK_名称, p.parseIdent)
	p.registerPrefix(token.TK_数, p.parseIntLiteral)
	p.registerPrefix(token.TK_布尔, p.parseBool)
	p.registerPrefix(token.LPAREN, p.parseGroupedExpr)
	p.registerPrefix(token.NOT, p.parsePrefixExpr)
	p.registerPrefix(token.SUB, p.parsePrefixExpr)
	p.registerPrefix(token.IF, p.parseIfExpr)
	p.registerPrefix(token.TK_若, p.解若之句)
	p.registerPrefix(token.FOR, p.parseForExpr)

	p.infixParseFns = make(map[token.TokenType]infixParseFn)
	p.registerInfix(token.ADD, p.parseInfixExpr)
	p.registerInfix(token.SUB, p.parseInfixExpr)
	p.registerInfix(token.MUL, p.parseInfixExpr)
	p.registerInfix(token.QUO, p.parseInfixExpr)
	p.registerInfix(token.EQL, p.parseInfixExpr)
	p.registerInfix(token.NOT_EQL, p.parseInfixExpr)
	p.registerInfix(token.GTR, p.parseInfixExpr)
	p.registerInfix(token.LSS, p.parseInfixExpr)
	p.registerInfix(token.ASSIGN, p.parseInfixExpr)
	p.registerInfix(token.LPAREN, p.parseCallExpr)

	p.nextToken()
	p.nextToken()

	return p
}

func (p *Parser) registerPrefix(t token.TokenType, fn prefixParseFn) {
	p.prefixParseFns[t] = fn
}

func (p *Parser) registerInfix(t token.TokenType, fn infixParseFn) {
	p.infixParseFns[t] = fn
}

func (p *Parser) Errors() []string {
	return p.errors
}

func (p *Parser) nextToken() {
	p.token = p.peek
	p.peek = p.lexer.NextToken()

	fmt.Printf("TOKEN:{cur:%s,peek:%s}\n", p.token, p.peek)
}

func (p *Parser) ParseProgram() *ast.Program {
	prog := &ast.Program{}
	prog.Stmts = []ast.Stmt{}

	for p.token.Type != token.EOF {
		stmt := p.parseStmt()
		if stmt != nil {
			prog.Stmts = append(prog.Stmts, stmt)
		}
		p.nextToken()
	}
	return prog
}

func (p *Parser) parseStmt() ast.Stmt {
	if p.token.Type == token.TK_左方 {
		return p.解方之句()
	}
	if p.token.Type == token.TK_令 {
		return p.解令之句()
	}
	if p.token.Type == token.VAR {
		return p.parseVarStmt()
	}
	return p.parseExprStmt()
}

const (
	_ int = iota
	PREC_LOWEST
	PREC_VARDECL
	PREC_ASSIGN
	PREC_EQUALS
	PREC_COMPARE
	PREC_SUM
	PREC_PRODUCT
	PREC_UNARY
	PREC_CALL
)

var precs = map[token.TokenType]int{
	token.ASSIGN:  PREC_ASSIGN,
	token.EQL:     PREC_EQUALS,
	token.NOT_EQL: PREC_EQUALS,
	token.LSS:     PREC_COMPARE,
	token.GTR:     PREC_COMPARE,
	token.ADD:     PREC_SUM,
	token.SUB:     PREC_SUM,
	token.MUL:     PREC_PRODUCT,
	token.QUO:     PREC_PRODUCT,
	token.LPAREN:  PREC_CALL,
}

func (p *Parser) parseExprStmt() *ast.ExprStmt {
	stmt := &ast.ExprStmt{Token: p.token}

	stmt.Expr = p.parseExpr(PREC_LOWEST)

	return stmt
}

func (p *Parser) parseExpr(prec int) ast.Expr {
	prefixFn := p.prefixParseFns[p.token.Type]
	if prefixFn == nil {
		p.noPrefixParseFnError(p.token.Type)
		return nil
	}

	leftExp := prefixFn()

	for !p.peekTokenIs(token.SEMICOLON) && prec < p.peekPrec() {
		infixFn := p.infixParseFns[p.peek.Type]
		if infixFn == nil {
			return leftExp
		}

		p.nextToken()
		leftExp = infixFn(leftExp)
	}

	return leftExp
}

func (p *Parser) peekTokenIs(t token.TokenType) bool {
	return p.peek.Type == t
}

func (p *Parser) noPrefixParseFnError(t token.TokenType) {
	msg := fmt.Sprintf("no prefix parse function for %s found", t)
	p.errors = append(p.errors, msg)
}

func (p *Parser) peekPrec() int {
	if p, ok := precs[p.peek.Type]; ok {
		return p
	}
	return PREC_LOWEST
}

func (p *Parser) parseIntLiteral() ast.Expr {
	lit := &ast.IntLiteral{Token: p.token}

	value, err := strconv.ParseInt(string(p.token.Literal), 0, 32)
	if err != nil {
		msg := fmt.Sprintf("could not parse %q as integer", p.token.Literal)
		p.errors = append(p.errors, msg)
		return nil
	}

	lit.Value = int(value)
	return lit
}

func (p *Parser) parseIdent() ast.Expr {
	return &ast.Ident{Token: p.token, Value: string(p.token.Literal)}
}

func (p *Parser) parseBool() ast.Expr {
	return &ast.BoolLiteral{Token: p.token, Value: string(p.token.Literal) == "true"}
}

func (p *Parser) parseInfixExpr(left ast.Expr) ast.Expr {
	expr := ast.InfixExpr{
		Token:    p.token,
		Operator: string(p.token.Literal),
		Left:     left,
	}

	prec := p.curPrec()
	p.nextToken()
	expr.Right = p.parseExpr(prec)
	return &expr
}

func (p *Parser) curPrec() int {
	if p, ok := precs[p.token.Type]; ok {
		return p
	}
	return PREC_LOWEST
}

func (p *Parser) parseGroupedExpr() ast.Expr {
	p.nextToken()

	expr := p.parseExpr(PREC_LOWEST)

	if !p.expectPeek(token.RPAREN) {
		return nil
	}

	return expr

}

func (p *Parser) expectPeek(t token.TokenType) bool {
	if p.peekTokenIs(t) {
		p.nextToken()
		return true
	} else {
		p.peekError(t)
		return false
	}
}

func (p *Parser) peekError(t token.TokenType) {
	err := fmt.Sprintf("expected next token to be %s, got %s instead", t, p.peek.Type)
	p.errors = append(p.errors, err)
}

func (p *Parser) parsePrefixExpr() ast.Expr {
	expr := &ast.PrefixExpr{
		Token:    p.token,
		Operator: string(p.token.Literal),
	}

	p.nextToken()

	expr.Right = p.parseExpr(PREC_UNARY)
	return expr
}

func (p *Parser) 解令之句() *ast.VarStmt {
	// 令关键字
	stmt := &ast.VarStmt{
		Token: p.token,
	}
	p.nextToken()

	// 变量名称
	name := p.parseIdent()
	stmt.Name = name.(*ast.Ident)
	p.nextToken()

	// TODO: 解析变量类型

	// {= expr}
	if p.token.Type == token.TK_为 {
		p.nextToken()

		// 解析赋值的变量表达式
		value := p.parseExpr(PREC_LOWEST)
		stmt.Value = value
	}
	return stmt
}

// var name = value
func (p *Parser) parseVarStmt() *ast.VarStmt {
	// var关键字
	stmt := &ast.VarStmt{
		Token: p.token,
	}
	p.nextToken()

	// 变量名称
	name := p.parseIdent()
	stmt.Name = name.(*ast.Ident)
	p.nextToken()

	// TODO: 解析变量类型

	// {= expr}
	if p.token.Type == token.ASSIGN {
		p.nextToken()

		// 解析赋值的变量表达式
		value := p.parseExpr(PREC_LOWEST)
		stmt.Value = value
	}
	return stmt

}

func (p *Parser) parseIfExpr() ast.Expr {
	expr := &ast.IfExpr{Token: p.token}
	// skip 'if'
	p.nextToken()

	expr.Condition = p.parseExpr(PREC_LOWEST)

	if !p.expectPeek(token.LBRACE) {
		return nil
	}

	expr.Then = p.parseBlockStmt()

	if p.peekTokenIs(token.ELSE) {
		p.nextToken() // now cur token is `else`

		// 如果后面紧跟着`if`，则将后面的`if`语句解析成一个ExprStmt，放入到一个空的BlockStmt中
		if p.peekTokenIs(token.IF) {
			p.nextToken() // now cur token is `if`
			ifExpr := p.parseIfExpr()
			stmt := &ast.ExprStmt{
				Token: p.token,
				Expr:  ifExpr,
			}
			block := &ast.BlockStmt{Token: p.token, Stmts: []ast.Stmt{
				stmt,
			}}
			expr.Else = block
		} else {

			if !p.expectPeek(token.LBRACE) {
				return nil
			}

			expr.Else = p.parseBlockStmt()
		}
	}

	return expr
}

func (p *Parser) parseBlockStmt() *ast.BlockStmt {
	block := &ast.BlockStmt{Token: p.token}
	block.Stmts = []ast.Stmt{}

	// skip {
	p.nextToken()

	for !(p.token.Type == token.RBRACE || p.token.Type == token.EOF) {
		stmt := p.parseStmt()
		if stmt != nil {
			block.Stmts = append(block.Stmts, stmt)
		}
		p.nextToken()
	}

	return block

}

func (p *Parser) parseForExpr() ast.Expr {
	expr := &ast.ForExpr{Token: p.token}
	// skip "for"
	p.nextToken()

	initial := p.parseStmt()

	// 判断单条件for循环，即 for <condition> { <body> }形式
	if p.peekTokenIs(token.LBRACE) {
		condStmt, ok := initial.(*ast.ExprStmt)
		if !ok {
			return nil
		}
		condition := condStmt.Expr

		p.nextToken()
		expr.Body = p.parseBlockStmt()
		expr.Condition = condition
		return expr
	}

	// skip ';'
	if !p.expectPeek(token.SEMICOLON) {
		return nil
	}
	p.nextToken()

	condition := p.parseExpr(PREC_LOWEST)

	// skip ';'
	if !p.expectPeek(token.SEMICOLON) {
		return nil
	}
	p.nextToken()

	step := p.parseStmt()

	if !p.expectPeek(token.LBRACE) {
		return nil
	}

	body := p.parseBlockStmt()

	expr.Initial = initial
	expr.Condition = condition
	expr.Step = step
	expr.Body = body

	return expr
}

func (p *Parser) parseParams() []*ast.Param {
	params := []*ast.Param{}

	// 直接遇到')'，函数参数表为空
	if p.peekTokenIs(token.RPAREN) {
		p.nextToken()
		return params
	}

	// skip '('
	p.nextToken()

	name := p.parseIdent()
	p.nextToken()
	typ := p.parseType()
	param := &ast.Param{
		Name: name.(*ast.Ident),
		Type: typ,
	}
	params = append(params, param)

	for p.peekTokenIs(token.COMMA) {
		p.nextToken()
		p.nextToken()
		name := p.parseIdent()
		p.nextToken()
		typ := p.parseType()
		param := &ast.Param{
			Name: name.(*ast.Ident),
			Type: typ,
		}
		params = append(params, param)
	}

	if !p.expectPeek(token.RPAREN) {
		return nil
	}

	return params
}

func (p *Parser) parseType() ast.Type {
	if string(p.token.Literal) == "int" {
		return ast.Int
	} else {
		return ast.Bool
	}
}

func (p *Parser) parseCallExpr(fn ast.Expr) ast.Expr {
	fmt.Printf("parsing call expr")
	expr := &ast.CallExpr{Token: p.token, Fn: fn}
	expr.Args = p.parseCallArgs()
	return expr
}

func (p *Parser) parseCallArgs() []ast.Expr {
	args := []ast.Expr{}

	// '()'的情况
	if p.peekTokenIs(token.RPAREN) {
		p.nextToken()
		return args
	}

	// skip '('
	p.nextToken()
	args = append(args, p.parseExpr(PREC_LOWEST))

	for p.peekTokenIs(token.COMMA) {
		p.nextToken()
		p.nextToken()
		args = append(args, p.parseExpr(PREC_LOWEST))
	}

	if !p.expectPeek(token.RPAREN) {
		return nil
	}

	return args
}

func (p *Parser) 解方之句() *ast.FnDeclStmt {
	stmt := &ast.FnDeclStmt{
		Token: p.token,
	}
	// 解析【
	p.nextToken()

	// 解析函数名称
	name := p.parseIdent()
	stmt.Name = name.(*ast.Ident)

	// 解析 】
	if !p.expectPeek(token.TK_右方) {
		fmt.Printf("函数名称应当以【】包括")
		return nil
	}

	if !p.expectPeek(token.TK_冒号) {
		fmt.Printf("函数定义应当以冒号“：”开头")
		return nil
	}

	fmt.Printf("函数名：%s\n", stmt.Name.String())

	stmt.Body = p.解句之多(token.TK_句号)

	if !(p.token.Type == token.TK_句号) {
		fmt.Printf("函数定义应以句号“。”结尾")
		return nil
	}

	return stmt
}

func (p *Parser) 解句之多(end token.TokenType) *ast.BlockStmt {
	block := &ast.BlockStmt{Token: p.token}
	block.Stmts = []ast.Stmt{}

	for !(p.token.Type == end || p.token.Type == token.EOF) {
		stmt := p.parseStmt()
		block.Stmts = append(block.Stmts, stmt)
		p.nextToken()
	}

	return block
}

func (p *Parser) 解若之句() ast.Expr {
	expr := &ast.IfExpr{Token: p.token}
	// 解析 '若'
	p.nextToken()

	expr.Condition = p.parseExpr(PREC_LOWEST)

	if !p.expectPeek(token.TK_则) {
		fmt.Printf("若之句应当以则开启第一分支")
		return nil
	}
	if !p.expectPeek(token.TK_冒号) {
		fmt.Printf("若之句的则分支应当以：开头")
		return nil
	}

	expr.Then = p.解句之多(token.TK_否则)

	if p.token.Type == token.TK_否则 {
		p.nextToken()
		expr.Else = p.解句之多(token.TK_句号)
	}

	return expr
}
